﻿namespace com.stifel.SharePoint
{
    using System;
    using System.Collections.Generic;

    using Microsoft.SharePoint.Administration;

    public class ULS : SPDiagnosticsServiceBase
    {
        #region Fields

        static ULS _Current;

        #endregion Fields

        #region Constructors

        ULS( )
            : base("Uls Logging Service", SPFarm.Local)
        {
        }

        #endregion Constructors

        #region Enumerations

        public enum Area
        {
            FeatureInfrastructure,
            Fields,
            General,
            TimerJob,
            WebControls,
            WebParts,
            WorkflowInfrastructure
        }

        #endregion Enumerations

        #region Properties

        public static ULS Current
        {
            get
            {
                if ( _Current == null )
                    _Current = new ULS( );
                return _Current;
            }
        }

        #endregion Properties

        #region Methods

        public static void LogCritical( Area area, string message )
        {
            SPDiagnosticsCategory category = Current.Areas[ xlatArea( area ) ].Categories[ internalCategory.ErrorCritical ];
            Current.WriteTrace( 0, category, TraceSeverity.Unexpected, message );
        }

        public static void LogCritical( Area area, string message, params object[ ] args )
        {
            LogCritical( area, string.Format( message, args ) );
        }

        public static void LogCritical( Area area, Exception exception, string message, params object[ ] args )
        {
            LogCritical( area, exception, string.Format( message, args ) );
        }

        public static void LogCritical( Area area, Exception exception, string message )
        {
            string s = string.Empty;
            if ( !string.IsNullOrEmpty( message ) && exception != null )
                s = string.Format( "{0}\r\n{1}\r\n{2}\r\n{3}", message, exception.Message, exception.InnerException, exception.StackTrace );
            else if ( exception != null )
                s = string.Format( "{0}\r\n{1}\r\n{2}", exception.Message, exception.InnerException, exception.StackTrace );
            else
                s = message;
            LogCritical( area, s );
        }

        public static void LogError( Area area, string message, params object[ ] args )
        {
            LogError( area, string.Format( message, args ) );
        }

        public static void LogError( Area area, Exception exception, string message, params object[ ] args )
        {
            LogError( area, exception, string.Format( message, args ) );
        }

        public static void LogError( Area area, Exception exception, string message )
        {
            string s = string.Empty;
            if ( !string.IsNullOrEmpty( message ) && exception != null )
                s = string.Format( "{0}\r\n{1}\r\n{2}\r\n{3}", message, exception.Message, exception.InnerException, exception.StackTrace );
            else if ( exception != null )
                s = string.Format( "{0}\r\n{1}\r\n{2}", exception.Message, exception.InnerException, exception.StackTrace );
            else
                s = message;
            LogError( area, s );
        }

        public static void LogError( Area area, string message )
        {
            SPDiagnosticsCategory category = Current.Areas[ xlatArea( area ) ].Categories[ internalCategory.Error ];
            Current.WriteTrace( 0, category, TraceSeverity.Unexpected, message );
        }

        public static void LogMessage( Area area, string message )
        {
            SPDiagnosticsCategory category = Current.Areas[ xlatArea( area ) ].Categories[ internalCategory.Information ];
            Current.WriteTrace( 0, category, TraceSeverity.Verbose, message );
        }

        public static void LogMessage( Area area, string message, params object[ ] args )
        {
            LogMessage( area, string.Format( message, args ) );
        }

        public static void LogWarning( Area area, string message )
        {
            SPDiagnosticsCategory category = Current.Areas[ xlatArea( area ) ].Categories[ internalCategory.Warning ];
            Current.WriteTrace( 0, category, TraceSeverity.Unexpected, message );
        }

        public static void LogWarning( Area area, string message, params object[ ] args )
        {
            LogWarning( area, string.Format( message, args ) );
        }

        protected override IEnumerable<SPDiagnosticsArea> ProvideAreas( )
        {
            List<SPDiagnosticsArea> areas = new List<SPDiagnosticsArea> {
                new SPDiagnosticsArea( internalArea.FeatureInfrastructure,
                    new List<SPDiagnosticsCategory>{
                        new SPDiagnosticsCategory( internalCategory.Error, TraceSeverity.Verbose, EventSeverity.Error ),
                        new SPDiagnosticsCategory( internalCategory.ErrorCritical, TraceSeverity.Verbose, EventSeverity.ErrorCritical ),
                        new SPDiagnosticsCategory( internalCategory.Warning, TraceSeverity.Verbose, EventSeverity.Warning ),
                        new SPDiagnosticsCategory( internalCategory.Information, TraceSeverity.Verbose, EventSeverity.Information )
                    }
                ),
                new SPDiagnosticsArea( internalArea.Fields,
                    new List<SPDiagnosticsCategory>{
                        new SPDiagnosticsCategory( internalCategory.Error, TraceSeverity.Verbose, EventSeverity.Error ),
                        new SPDiagnosticsCategory( internalCategory.ErrorCritical, TraceSeverity.Verbose, EventSeverity.ErrorCritical ),
                        new SPDiagnosticsCategory( internalCategory.Warning, TraceSeverity.Verbose, EventSeverity.Warning ),
                        new SPDiagnosticsCategory( internalCategory.Information, TraceSeverity.Verbose, EventSeverity.Information )
                    }
                ),
                new SPDiagnosticsArea( internalArea.General,
                    new List<SPDiagnosticsCategory>{
                        new SPDiagnosticsCategory( internalCategory.Error, TraceSeverity.Verbose, EventSeverity.Error ),
                        new SPDiagnosticsCategory( internalCategory.ErrorCritical, TraceSeverity.Verbose, EventSeverity.ErrorCritical ),
                        new SPDiagnosticsCategory( internalCategory.Warning, TraceSeverity.Verbose, EventSeverity.Warning ),
                        new SPDiagnosticsCategory( internalCategory.Information, TraceSeverity.Verbose, EventSeverity.Information )
                    }
                ),
                new SPDiagnosticsArea( internalArea.TimerJob,
                    new List<SPDiagnosticsCategory>{
                        new SPDiagnosticsCategory( internalCategory.Error, TraceSeverity.Verbose, EventSeverity.Error ),
                        new SPDiagnosticsCategory( internalCategory.ErrorCritical, TraceSeverity.Verbose, EventSeverity.ErrorCritical ),
                        new SPDiagnosticsCategory( internalCategory.Warning, TraceSeverity.Verbose, EventSeverity.Warning ),
                        new SPDiagnosticsCategory( internalCategory.Information, TraceSeverity.Verbose, EventSeverity.Information )
                    }
                ),
                new SPDiagnosticsArea( internalArea.WebControls,
                    new List<SPDiagnosticsCategory>{
                        new SPDiagnosticsCategory( internalCategory.Error, TraceSeverity.Verbose, EventSeverity.Error ),
                        new SPDiagnosticsCategory( internalCategory.ErrorCritical, TraceSeverity.Verbose, EventSeverity.ErrorCritical ),
                        new SPDiagnosticsCategory( internalCategory.Warning, TraceSeverity.Verbose, EventSeverity.Warning ),
                        new SPDiagnosticsCategory( internalCategory.Information, TraceSeverity.Verbose, EventSeverity.Information )
                    }
                ),
                new SPDiagnosticsArea( internalArea.WebParts,
                    new List<SPDiagnosticsCategory>{
                        new SPDiagnosticsCategory( internalCategory.Error, TraceSeverity.Verbose, EventSeverity.Error ),
                        new SPDiagnosticsCategory( internalCategory.ErrorCritical, TraceSeverity.Verbose, EventSeverity.ErrorCritical ),
                        new SPDiagnosticsCategory( internalCategory.Warning, TraceSeverity.Verbose, EventSeverity.Warning ),
                        new SPDiagnosticsCategory( internalCategory.Information, TraceSeverity.Verbose, EventSeverity.Information )
                    }
                ),
                new SPDiagnosticsArea( internalArea.WorkflowInfrastructure,
                    new List<SPDiagnosticsCategory>{
                        new SPDiagnosticsCategory( internalCategory.Error, TraceSeverity.Verbose, EventSeverity.Error ),
                        new SPDiagnosticsCategory( internalCategory.ErrorCritical, TraceSeverity.Verbose, EventSeverity.ErrorCritical ),
                        new SPDiagnosticsCategory( internalCategory.Warning, TraceSeverity.Verbose, EventSeverity.Warning ),
                        new SPDiagnosticsCategory( internalCategory.Information, TraceSeverity.Verbose, EventSeverity.Information )
                    }
                ),
            };
            return areas;
        }

        static string xlatArea( Area area )
        {
            string a = string.Empty;
            switch ( area )
            {
                case Area.FeatureInfrastructure:
                    a = internalArea.FeatureInfrastructure;
                    break;
                case Area.Fields:
                    a = internalArea.Fields;
                    break;
                case Area.General:
                    a = internalArea.General;
                    break;
                case Area.TimerJob:
                    a = internalArea.TimerJob;
                    break;
                case Area.WebControls:
                    a = internalArea.WebControls;
                    break;
                case Area.WebParts:
                    a = internalArea.WebParts;
                    break;
                case Area.WorkflowInfrastructure:
                    a = internalArea.WorkflowInfrastructure;
                    break;
                default:
                    a = internalArea.General;
                    break;
            }
            return a;
        }

        #endregion Methods

        #region Nested Types

        class internalArea
        {
            #region Fields

            public const string FeatureInfrastructure = "Feature Infrastructure";
            public const string Fields = "Fields";
            public const string General = "General";
            public const string TimerJob = "Timer Job";
            public const string WebControls = "Web Controls";
            public const string WebParts = "Web Parts";
            public const string WorkflowInfrastructure = "Workflow Infrastructure";

            #endregion Fields
        }

        class internalCategory
        {
            #region Fields

            public const string Error = "Error";
            public const string ErrorCritical = "Error Critical";
            public const string Information = "Info";
            public const string Warning = "Warning";

            #endregion Fields
        }

        #endregion Nested Types
    }
}